#ifndef VPENTRANCE_H
#define VPENTRANCE_H

#include <vppacketqueue.h>
#include <vpframequeue.h>
#include <QObject>
#include <VpDemuxThread.h>
#include <VpDecodeVideoThread.h>
#include <VpDecodeAudioThread.h>
#include <vpclock.h>

extern "C"
{
#include "libavutil/imgutils.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "SDL.h"
#undef main
}

#define AV_SYNC_THRESHOLD_MIN      0.04
#define AV_SYNC_THRESHOLD_MAX      0.5
#define MAX_FRAME_DURATION         0.1

void audio_sdl_callback(void *userdata, uint8_t *stream, int len);

class VpEntrance : public QObject
{
    Q_OBJECT
public:
    int                       m_video_stream_idx;
    int                       m_audio_stream_idx;
    int                       m_serial;
    int                       m_sws_serial;
    int                       m_swr_serial;
    int                       m_seek_time;
    int                       m_audio_volume;
    bool                      m_stop;
    bool                      m_pause;
    bool                      m_seek_req;
    double                    m_audio_clock;
    double                    m_video_clock;
    double                    m_audio_callback_time;
    double                    m_audio_can_write_size;
    double                    m_wanted_nb_samples;
    unsigned int              m_audio_buffer_size;
    unsigned int              m_audio_buffer_size1;
    unsigned int              m_audio_buffer_idx;
    uint8_t*                  m_audio_buffer;
    uint8_t*                  m_audio_buffer1;
    AVFormatContext*          m_fmt_ctx;
    AVCodecContext*           m_video_codec_ctx;
    AVCodecContext*           m_audio_codec_ctx;
    VpPacketQueue             m_video_pkt_list;
    VpPacketQueue             m_audio_pkt_list;
    VpFrameQueue              m_video_fme_list;
    VpFrameQueue              m_audio_fme_list;
    VpDemuxThread             m_demux_th;
    VpDecodeVideoThread       m_decode_video_th;
    VpDecodeAudioThread       m_decode_audio_th;
    mutex                     m_mutex;
    condition_variable        m_cond;
    condition_variable        m_pause_cond;
    condition_variable        m_wait_for_stop_cond;
    VpClock                   m_audclk;
    VpClock                   m_vidclk;
    VpFrame                   m_last_video_frame;
    SDL_AudioDeviceID         m_audioDevice_id;
    enum STATE {
        STOP = 0,
        PLAYING,
        PAUSE
    }                         m_state;
    struct VIDEO_PARAMS
    {
        int             width;
        int             height;
        int             serial;
        AVPixelFormat   format;
        SwsContext*     sws_ctx;
        VIDEO_PARAMS() {
            width   = 0;
            height  = 0;
            serial  = 0;
            format  = AV_PIX_FMT_YUV420P;
            sws_ctx = NULL;
        }
    }                         m_video_params;
    VIDEO_PARAMS              m_video_params_chg;

    struct AUDIO_PARAMS
    {
        int             freq;
        int             frame_size;
        int             bytes_per_sec;
        int             serial;
        AVChannelLayout ch_layout;
        AVSampleFormat  format;
        SwrContext*     swr_ctx;
        AUDIO_PARAMS() {
            serial  = 0;
            format  = AV_SAMPLE_FMT_S16;
            swr_ctx = NULL;
        }
    }                         m_audio_params;
    AUDIO_PARAMS              m_audio_params_src;
    AUDIO_PARAMS              m_audio_params_backup;
    AUDIO_PARAMS              m_audio_params_chg;
    static int                s_RUNNING_THREAD_NUM;

private:
    static VpEntrance*        s_INSTANCE;

private:
    explicit    VpEntrance           (QObject *parent = nullptr);
                VpEntrance           (const VpEntrance&)            = delete;
    VpEntrance& operator=            (const VpEntrance&) = delete;
    bool        start_send_Image     (VpFrameQueue *video_fme_queue, struct VIDEO_PARAMS *video_params);
    bool        start_initial        (string file_name, int width, int height);
    void        release_resource     ();


public:
    int                input_audio_buffer   (VpFrame src);
    bool               start                (string file_name, int width, int height);
    void               stop                 ();
    void               start_play           ();
    void               alter_speed          (double speed);
    void               pause_or_resume      ();
    void               alter_video_size     (int width, int height);
    double             compute_target_delay (double duration);
    static void        work_send_image      (VpEntrance* vp_entrance, VpFrameQueue *video_fme_queue, struct VIDEO_PARAMS *video_params);
    static VpEntrance* getInstance          ();
    static bool        initial              (VpEntrance* vp_entrance, string file_name, int width, int height);


signals:
    void        sendImage       (uint8_t* data, int width, int height);
    void        sendSeconds     (int seconds);
    void        sendAllSeconds  (int all_seconds);

public slots:
    void               seek_time            (int seek_time);
    void               set_audio_volume     (int volume);
};

#endif // VPENTRANCE_H
